This code sample demonstrates several important techniques that can be used in the creation of a guide file. It demonstrates how to write a background only helper application and how to use it to store and access variables which are used by the guide. In addition it shows how to add a coach mark handler.
Why you might want to store variables
Apple Guide has many advantages over other help systems but has several drawbacks. One is that it is not easy to keep track of what the user has already done. This becomes a particular problem if you are writing a tutorial. For example, your tutorial might have 10 different lessons which the user may need to complete over several days. How can the user be sure that they have gone back to the point where they left the tutorial and not skipped stages? One way to do this is to store variables within an application.
Why you might want to use a helper application
It is not always possible for the guide author to have access to the application's source. This is especially true if they are writing a guide for somebody else's application. You may also want to add complex Apple Events to an application that has been factored but not fully scripted. The way to do this is to write a small background only application referred to as a helper application. Your guide sends Apple Events or context checks to the helper application and in turn the helper app makes changes, creates complex events, etc. and passes these on to the application. In this sample the helper application is used to store variables. The background only application is based on the SmallDaemon sample on the toolchest CD. This was originally written by Greg Robbins based on code by C.K. Haun.
How to use the Tutorial
Double click "Open this App" and open the tutorial in the help menu. Apple Guide will start up presenting you with a single list access window. The application is nothing more than a simple shell application that allows you to open several windows.
"Tutorial"
"From Start"
This will take you through each lesson in order, regardless whether you've completed the lesson already.
"Skip completed lessons"
This will only take you through each lessons that have NOT been completed.
" Lesson 1",
" Lesson 2",
" Lesson 3"
Lets you go straight to a lesson whether you have seen it already or not.
House Keeping
"Reset the Lesson plan"
This clears all previously completed lessons.
"What is the Lesson Status"
Lets you find out which lessons if any have been completed.
Scripts
"StartHelperApp"
This script will start the background only application called "AGHelperApp".
"QuitHelperApp"
This script will quit the background only application called "AGHelperApp".
Building
"AGHelperApp" compiles under :
Metrowerks CodeWarrior 9 68K and PPC
MPW E.T.O. #20- Symantec C++ for MPW, MrC
MPW build notes
Before building you need to move AppleGuideGlueLib.xcoff from Dev.CD Jul 96 SDK1:Development Kits (Disc 1):Apple Guide:Engineering:Interfaces: to MPW's PPCLibraries folder.
"AGHelperApp.make" builds a fat version of the helper application.
Metrowerks build notes
"AGHelperApp MW-PPC.µ" build a PPC version of the application.
"AGHelperApp MW-68k.µ" build a 68k version of the application.
Files
AGHelper App Source
AGHelper.c
- Was originally called cSmallDaemon
- Contains "main" function which has the calls to install and remove AGValues.
- Handles the event loop
AGValues.c,
AGValues.h
- Contains the code for Apple Events and context checks to allow Apple Guides to store and retrieve variables.
- Installs and removes Apple Events and context check handlers
AGHelper.r
- Contains the 'SIZE' resources in a text format. This is used by the MPW make files.
Guide Source
Content
- Contains all the Apple Script commands to build the tutorial guide
Resources,
Setup
- cut down versions of the Standard Resources and Standard Setup
Apple Script Source
StartHelperApp,
StartHelperApp Text
- Compiled and text version of a script that launches AGHelperApp
QuitHelperApp,
QuitHelperApp Text
- Compiled and text version of a script that quits AGHelperApp
How the interesting stuff works
How to write context check handlers
Context checks are defined in Apple Script in the following format.
Note that you can use <DCC> as an abbreviation. The targetApp's context check handler called coderResSpec will be called and passed any additional parameters. Information about additional parameters can be found on page 10-173 of Apple Guide complete. If you want to default one or more of the additional parameters, after the parameter type add a colon, then the default value. For example, the follow checks will all do the same thing - send check 'Chck' to application 'MyAp' with the parameters 13 and 15:
<DCC> "Check_2_Longs", 'Chck', 'MyAp', LONG, LONG
<If> (Check_2_Longs(13,15))
<DCC> "Check_1st_Default", 'Chck', 'MyAp', LONG:13, LONG
MyContextCallBack is the function name of the handler, 'Vals' is used to identify it and corresponds to the codeResSpec in the guides <DCC> command, the 0 is a refcon which in this case isn't used and contextRefNum is a global that will be needed when the application quits. To remove the handler use
The context check handler must be in the following format.
pascal OSErr MyContextCallBack( Ptr pInputData,
Size inputDataSize,
Ptr *ppOutputData,
Size *pOutputDataSize,
AGAppInfoHdl hAppInfo )
pInputData and inputDataSize are used to pass the additional parameters from the guide file. ppOutputData and pOutputDataSize are used to return the information. hAppInfo contains information about the codeResSpec and the refCon.
The additional parameters are passed in pInputData and inputDataSize and a structure should be created that matches them. Therefore, if the additional parameters contained two longs, then the structure should contain longs. Using an example from above, the structure would need to be:
The context check needs to evaluate the parameters passed to it and then decide whether it needs to return true or false. This is passed back in ppOutputData and pOutputDataSize, however as this is part of a far wider mechanism you can't simply pass back the Boolean but you must create a pointer and move the Boolean's value into it. There is a routine in the sample that does all the work for you. Note that Apple Guide is responsible for de-allocating this pointer not the helper app.
OSErr MySetContextResult( Boolean result,
Ptr *outMessage,
Size *outSize )
{
Ptr pOut;
Size theSize = sizeof ( Boolean );
OSErr theErr = noErr;
pOut = NewPtr (theSize);
if ( pOut )
{
BlockMove( (void *)&result, pOut, theSize );
*outSize = theSize;
*outMessage = pOut;
}
else
theErr = MemError();
return theErr;
}
In the context check:
...
...
// Set up the return values ppOutputData and pOutputDataSize
MyObjectCoachCallBack is the function name of the handler, the 0 is a refcon which in this case isn't used and coachRefNum is a global that will be needed when the application quits. To remove the handler use
theErr = AGRemoveCoachHandler( &coachRefNum );
The coach mark handler must be in the following format:
pascal OSErr MyObjectCoachCallBack ( Rect *pRect, Ptr name, long refCon )
{
OSErr theErr = noErr;
SetRect ( pRect, 100,100, 200,200);
return theErr;
}
The object name from the guide is passed to the handler in the name parameter. It arrives as a null terminated string and can be interrogated to find out which object you wish to access. You must then return its rect in global coordinates in pRect. As this is a demonstration, it only returns a 100*100 rect.
What's been done to SmallDaemon
Very few changes have been made to the original sample, except to make it compile under the latest compilers. The biggest change is to add the calls that install and remove AGValues to main(). The bulk of the changes are in the files AGValues.c and AGValues.h.
Globals
Storage has been provide for 100 variables. In 'C' this provides an array from 0-99, however in the guide we are going to use values of 1-3. For neatness sake, these will be mapped from 1-3 to 0-2.
#define kMaxAGEntries 100
long gAGValues[kMaxAGEntries];
Also references must be stored for the coach mark and context check handlers:
AGCoachRefNum coachRefNum;
AGContextRefNum contextRefNum;
How to install and remove the handlers
The handlers are installed by InitAGStuff. First it clears all the stored variables. Then it installs a coach mark handler, a context check handler and then the Apple Events.
Setting and clearing of the variables is done by Apple Events. Each event has a specific ID and no passed parameters. You will probably need to make these obvious by their ID. For instance to set and clear value 1, use the event ID's 'Set1' and 'Clr1' . The Apple Event handlers would look like the following:
Checking the state of the variables is handled by Apple Guide context checks. Two parameters - in this case longs - are passed by the guide file to the application.
If the first parameter, command, contains a 0, then a check is made to see if the value is 0. If it contains a 1, then the check sees it the value is non-0. Index is used to define which variable to check. The full context check looks like the following:
pascal OSErr MyContextCallBack( Ptr pInputData,
Size inputDataSize,
Ptr *ppOutputData,
Size *pOutputDataSize,
AGAppInfoHdl hAppInfo )
{
OSErr theErr = noErr;
Boolean checkResult = false;
// Check the index is within range
if (((PassedAGParamPtr)pInputData)->index <= kMaxAGEntries)
{
// Work out whether we need to return true or false
"ClearValues" sends the Apple Event 'Cler' of event class 'Vals' to the application with the creator type 'AgHp'. This is defined in the application to clear all variables to 0.
"SetFlag1" sends the Apple Event 'Set1' of event class 'Vals' to the application with the creator type 'AgHp'. This is defined in the application to set the first variables to 1.
"ClearFlag1" sends the Apple Event 'Clr1' of event class 'Vals' to the application with the creator type 'AgHp'. This is defined in the application to set the first variables to 0.
etc.
To use them, use an <On Panel Hide>, for example:
<On Panel Hide> SetFlag1()
Defining the context checks in the guide
Context checks are defined to find out whether any variable is set or cleared, or specific variables are set.
<DCC> "IsFlagSet", 'Vals', 'AgHp', LONG:1, LONG
<DCC> "IsFlagClear", 'Vals', 'AgHp', LONG:0, LONG
<DCC> "Flag1Set", 'Vals', 'AgHp', LONG:1, LONG:1
<DCC> "Flag2Set", 'Vals', 'AgHp', LONG:1, LONG:2
<DCC> "Flag3Set", 'Vals', 'AgHp', LONG:1, LONG:3
If you want to check whether the first variable has been set, you can use one of two checks:
<If> ( isFlagSet( 1 ) )
<If> ( Flag1Set() )
Note that because the parameters have default values in the definitions, those parameters are not included when they are used.
Making sure the helper app is launched
To make sure the helper app is launched you need to trigger it from an Apple Script. You may also want to use a script to make it quit. The script needs to be compiled. Note that if you change the helper, or main app's creator, you will need to recompile the script and then recompile the guide. The script that starts the helper app is called "StartHelperApp". It contains the following Apple Script commands :
tell application "AGHelperApp"
launch
end tell
The script that quits the app, is "QuitHelperApp". It contains the following Apple Script commands :
tell application "AGHelperApp"
quit
end tell
Once compiled the scripts need to be triggered before the events and context checks can be used. For example the first panel in "Tutorial Skip lessons" sequence called "Tutorial Intro" :
To mark a sequence completed, use an <On Panel Hide> command with a suitable event to set the variable . For example to mark the sequence "Lesson 1" as completed, the last panel contains:
<Define Panel> "Lesson 1 Panel Outro"
<On Panel Hide> SetFlag1()
Last panel in Lesson 1.
This may contain an acknowledgment that the lesson has been completed.
It sets flag 1 with :
"<On Panel Hide> SetFlag1()"
<End Panel>
Further things YOU could do
If you feel like playing with this app, there's a few ways you could improve it.
- Make the sample save all the variables to a preferences file when it quits and re-loads them when it starts
- Implement more variables and different ways of checking them.
- Add AGValues.c to your application and write a tutorial Guide!
Further Ref
- Apple Guide Complete is an almost essential volume if you are writing Apple Guide help systems. It is published by Addison-Wesley.
- Apple Guide Variables Technote.
Acknowledgments
Special thanks to :
Jason Hodges-Harris - for fixing the MPW build
Greg Robbins & C.K. Haun - for the original SmallDaemon sample